package 力扣;

/**
 假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如，数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] 。

 请找出其中最小的元素。

 示例 1：
 输入：nums = [3,4,5,1,2]
 输出：1
 示例 2：
 输入：nums = [4,5,6,7,0,1,2]
 输出：0
 示例 3：

 输入：nums = [1]
 输出：1
 */

public class _153寻找旋转排序数组中的最小值 {


    public int findMin(int[] nums) {
        // 前面一堆０，后面一堆１，然后寻找第一个１的二分问题
            int l = 0;
            int r = nums.length-1;
            while( l<r ){
                int  m = ( l+r)>>1;
                if( nums[m]<= nums[r]){//说明最小值肯定在 mid的左边
                     r = m;
                }else{
                    l = m+1;
                }

            }
            return nums[l];
    }
    //思路:使用二分法查找,需要考虑三种情况：
	/*

		采用二分法解答这个问题，
		mid = low + (high - low)/2
		需要考虑三种情况：
		(1)array[mid] > array[high]:
		出现这种情况的array类似[3,4,5,6,0,1,2]，此时最小数字一定在mid的右边。
		low = mid + 1
		(2)array[mid] == array[high]:
		出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1]，此时最小数字不好判断在mid左边
		还是右边,这时只好一个一个试 ，
		high = high - 1
		(3)array[mid] < array[high]:
		出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左
		边。因为右边必然都是递增的。
		high = mid
		注意这里有个坑：如果待查询的范围最后只剩两个数，那么mid 一定会指向下标靠前的数字
		比如 array = [4,6]
		array[low] = 4 ;array[mid] = 4 ; array[high] = 6 ;
		如果high = mid - 1，就会产生错误， 因此high = mid
	 */
    public int findMin2(int[] nums) {
        //非判断
        if( nums.length ==0 || nums ==null) return 0;

        int left = 0;
        int right = nums.length - 1;
        int mid = 0 ; //循环里面计算mid
        //确保旋转
        while(nums[left] >= nums[right]){
            if( right - left <=1){
                mid = right;
                break;
            }
            mid = (left + right) / 2;
            //判断中间数是否相等
            if(nums[left] == nums[mid] && nums[mid] == nums[right]){

                //判断相邻数是否相等
                if(nums[left+1]== nums[right-1]){ //继续查找最小数
                    left++;
                    right --;
                }else{ //不相等 mid的值为最小的索引
                    mid = nums[left+1] >nums[right-1] ? right-1 : left+1;

                }
            }else{
                //因为为旋转了,所以中间数后面一定是最小数
                if(nums[mid] >= nums[left]){
                    left =mid;
                }else{
                    right =mid;
                }

            }
        }
        //没旋转直接返回
        return nums[mid];
    }


}
